package com.xbongbong.pro.dataset.node;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.collect.Maps;
import com.xbongbong.paas.bi.pojo.DataSetNodeFieldPojo;
import com.xbongbong.paas.bi.pojo.DataSetNodeFilterPojo;
import com.xbongbong.paas.bi.pojo.DataSetNodeUnionPojo;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.bi.DataSetNodeTypeEnum;
import com.xbongbong.paas.enums.bi.XbbTableRefEnum;
import com.xbongbong.paas.pojo.BiExplainPojo;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.bi.commons.filter.SrTeamJoinHandler;
import com.xbongbong.pro.bi.commons.helper.StringHelper;
import com.xbongbong.pro.bi.commons.sql.SqlBuilderHandler;
import com.xbongbong.pro.bi.commons.sql.SqlInfo;
import com.xbongbong.pro.dataset.helper.JsonObjectHelper;
import com.xbongbong.pro.dataset.helper.JsqlParseHelper;
import com.xbongbong.pro.statistic.pojo.dto.SqlParseDTO;
import com.xbongbong.pro.statistics.help.CommonHelper;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.StringConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * @author gzt
 * @version 1.0
 * @Description -
 * @datetime - 2022/5/23-11:08
 * @since v1.0
 */
@Slf4j
@Component
public class UnionNodeStrategy implements NodeStrategy {
    @Resource
    JsqlParseHelper jsqlParseHelper;
    @Resource
    private SrTeamJoinHandler srTeamJoinHandler;
    
    @Override
    public void parseNodeToSql(SqlParseDTO sqlParseDTO) throws XbbException {
        String corpid = sqlParseDTO.getCorpid();
        String nodeId = sqlParseDTO.getNodeId();
        JSONObject jsonObject = sqlParseDTO.getJsonObject();
        Map<String, String> sqlNodes = SQL_NODES_THREAD_LOCAL.get();
        Map<String, String> nodeTypeThreadLocal = NODE_TYPE_THREAD_LOCAL.get();
        nodeTypeThreadLocal.put(nodeId,getNodeType());
        //DataSetNodeUnionPojo unionNode = jsonObject.toJavaObject(new TypeReference<DataSetNodeUnionPojo>() {});
        DataSetNodeUnionPojo unionNode = JSONObject.parseObject(JSON.toJSONString(jsonObject, SerializerFeature.DisableCircularReferenceDetect), DataSetNodeUnionPojo.class);
        int size = unionNode.getInput().size();
        if (size < BasicConstant.TWO){return;}
        HashMap<String, String> nodesSqlMap = Maps.newHashMap();
        for (int i = 0; i < size; i++) {
            String node = unionNode.getInput().get(i);
            String nodeSql = sqlNodes.get(node);
            nodesSqlMap.put(node, nodeSql);
        }
        List<DataSetNodeFieldPojo> unionNodeFields = unionNode.getField();
        List<DataSetNodeFieldPojo> hideField = unionNode.getHideField();
        if(CollectionsUtil.isNotEmpty(unionNodeFields) && CollectionsUtil.isNotEmpty(hideField)){
            jsqlParseHelper.reMoveRedundant(unionNodeFields,hideField);
            unionNodeFields.addAll(hideField);
        }
        HashMap<String, String> unionAttrMap = Maps.newHashMap();
        nodesSqlMap.keySet().forEach(node->{
            //throw new XbbException(ErrorCodeEnum.API_ERROR_263006);
            String nodeType = nodeTypeThreadLocal.get(node);
            String unionAttr = unionNodeFields.stream().map(field -> {
                Map<String, BiExplainPojo> srcB = field.getSrcB();
                BiExplainPojo biExplainPojo = srcB.get(node);
                String asField = field.getAttr();
                //字段类型
                Integer fieldType = field.getFieldType();
                if (StringUtils.isEmpty(asField) && Objects.nonNull(biExplainPojo)) {
                    //throw new XbbException(ErrorCodeEnum.API_ERROR_263006);
                    asField = StringUtil.getDataBaseString(biExplainPojo.getOriginalAttr());
                } else if(asField.contains(FieldTypeEnum.FORM_ID.getAlias())){
                    asField = StringUtil.getDataBaseString(asField);
                }
                String originalAttr = "";
                if (biExplainPojo == null) {
                    originalAttr = convertOwnerCO(fieldType,asField,asField,true);
                    return originalAttr;
                }
                //解决多层和单层join data外字段驼峰转下划线。多层的不需要转
                if (!Objects.equals(nodeType, DataSetNodeTypeEnum.JOIN.getAlias()) && !Objects.equals(nodeType,DataSetNodeTypeEnum.UNION.getAlias())){
                    originalAttr = StringUtil.getDataBaseString(biExplainPojo.getOriginalAttr());
                }else {
                    originalAttr = biExplainPojo.getOriginalAttr();
                    if(originalAttr.contains(FieldTypeEnum.FORM_ID.getAlias())){
                        originalAttr  = StringUtil.getDataBaseString(originalAttr);
                    }
                }
                if (StringUtils.isEmpty(originalAttr)) {
                    String preNull = XbbConstant.SQL_NULL;
                    if (Objects.equals(FieldTypeEnum.OWNERID.getType(),field) || Objects.equals(FieldTypeEnum.COUSERID.getType(),field)){
                        preNull = XbbConstant.L_B+XbbConstant.SINGLE_QUOTES+XbbConstant.SINGLE_QUOTES+XbbConstant.R_B;
                     }
                    originalAttr =  preNull+ XbbConstant.AS + asField;
                } else {
                    originalAttr = convertOwnerCO(fieldType,asField, originalAttr,false);
                }
                return originalAttr;
            }).collect(Collectors.joining(XbbConstant.SQL_COMMA));
            unionAttrMap.put(node,unionAttr);
        });
        String unionAttrs = unionNodeFields.stream().map(field -> {
            String asField = field.getAttr();
            Integer fieldType = field.getFieldType();
            if (StringUtils.isEmpty(asField)) {
                asField = field.getOriginalAttr();
            }else if(asField.contains(FieldTypeEnum.FORM_ID.getAlias())){
                asField = StringUtil.getDataBaseString(asField);
            }

            asField = CommonHelper.getConvertAttr(asField,fieldType);
            return asField;
        }).collect(Collectors.joining(XbbConstant.SQL_COMMA));
        HashMap<String, SqlBuilderHandler> sqlBuilderMap = getTeamJoinSqlBuilderHandlerHashMap(corpid, unionNode, nodesSqlMap, unionAttrMap);
        SqlBuilderHandler startSqlBuilder = SqlBuilderHandler.start();
        AtomicInteger mapIndex = new AtomicInteger();
        sqlBuilderMap.values().stream().forEach(sqlBuilder ->{
            mapIndex.getAndIncrement();
            if (mapIndex.get() == size){
                startSqlBuilder.append(sqlBuilder.end().getSql());
            }else {
                startSqlBuilder.append(sqlBuilder.end().getSql()).unionAll();
            }

        });
        SqlInfo sqlInfo = startSqlBuilder.end();
        SqlBuilderHandler sqlBuilderUnion = SqlBuilderHandler.start();
        String sql = sqlBuilderUnion.select(unionAttrs).from(StringHelper.addPreSuffix(sqlInfo.getSql(),true)).end().getSql();
        sqlNodes.putIfAbsent(nodeId,sql);
    }

    /**
     * @author  gzt
     * @Description append team拼接sql返回Map
     * @Date 19:50 2022/10/11
     * @param corpid
     * @param unionNode
     * @param hashMap
     * @param unionAttrMap
     * @return java.util.HashMap<java.lang.String,com.xbongbong.pro.bi.commons.sql.SqlBuilderHandler>
     * @throws
     **/

    private HashMap<String, SqlBuilderHandler> getTeamJoinSqlBuilderHandlerHashMap(String corpid,
                                                                                   DataSetNodeUnionPojo unionNode,
                                                                                   HashMap<String, String> hashMap, HashMap<String, String> unionAttrMap) {
        HashMap<String, SqlBuilderHandler> sqlBuilderMap = Maps.newHashMap();
        Map<String, List<DataSetNodeFilterPojo>> unionNodeFilter = unionNode.getFilter();
        hashMap.keySet().forEach(node->{
            JSONArray nodeArray = JsonObjectHelper.getJsonArray(unionNodeFilter.get(node));
            try {
                String nodeSql = hashMap.get(node);
                SqlBuilderHandler sqlBuilder = SqlBuilderHandler.start().append(nodeSql);
                Map<String, String> nodeFormIdMap = NODE_FORM_ID_THREAD_LOCAL.get();
                Map<String, StringBuffer> filterMap = new HashMap<>(XbbConstant.INITIALCAPACITY);
                if (nodeFormIdMap.containsKey(node)){//第一次合并处理。多层union、和第一层union过滤走不同逻辑
                    jsqlParseHelper.appendFilter(nodeArray, sqlBuilder, null, null, corpid, filterMap,false);
                    Map<String, String> nodeTableNameMap = NODE_TABLE_NAME_THREAD_LOCAL.get();
                    String tableName = nodeTableNameMap.get(node);
                    if (StringUtils.isNotEmpty(tableName)) {
                        sqlBuilder.append(XbbConstant.L_P, XbbConstant.R_P + XbbConstant.AS + tableName, true);
                    }
                    //团队表sql获取从input节点移到合并节点
                    boolean isPublicFlag = srTeamJoinHandler.isPublicFlag(null,nodeArray, tableName, false);
                    SqlBuilderHandler teamJoinSqlHBuilder = SqlBuilderHandler.start();
                    XbbTableRefEnum xbbTableRefEnum = XbbTableRefEnum.getByTable(tableName);
                    if (Objects.nonNull(xbbTableRefEnum)){
                        if (Objects.nonNull(filterMap)) {
                            StringBuffer condition = filterMap.get(nodeFormIdMap.get(node));
                            String teamName = CommonHelper.getTeamNameByBusinessType(xbbTableRefEnum.getCode());
                            if ((Objects.nonNull(teamName) && nodeSql.contains(teamName)) || Objects.nonNull(condition)){
                                srTeamJoinHandler.appendDataSetTeamJoinSql(teamJoinSqlHBuilder,condition, tableName,teamName, corpid, isPublicFlag);
                                //append团队表
                                String teamSql = teamJoinSqlHBuilder.end().getSql();
                                if (teamSql.length() > 0) {
                                    sqlBuilder.append(teamSql);
                                }
                            }
                        }
                    }
                    String unionAttr = unionAttrMap.get(node);
                    SqlBuilderHandler sqlBuilderHandler = SqlBuilderHandler.start()
                            .select(unionAttr)
                            .from(StringHelper.addPreSuffix(sqlBuilder.end().getSql(), true));
                    sqlBuilderMap.put(node, sqlBuilderHandler);
                }else {
                    String unionAttr = unionAttrMap.get(node);
                    SqlBuilderHandler sqlBuilderHandler = SqlBuilderHandler.start()
                            .select(unionAttr)
                            .from(StringHelper.addPreSuffix(sqlBuilder.end().getSql(), true));
                    jsqlParseHelper.appendFilter(nodeArray, sqlBuilderHandler, null, null, corpid, filterMap,true);
                    sqlBuilderMap.put(node, sqlBuilderHandler);
                }
            } catch (XbbException e) {
                log.error("UNION 节点解析异常",e);
            }
        });
        return sqlBuilderMap;
    }
    /**
     * @author  gzt
     * @Description 处理负责人、协同人
     * @Date 10:19 2022/12/5
     * @param fieldType
     * @param asField
     * @param originalAttr
     * @param isOAttrNull
     * @return java.lang.String
     * @throws
     **/

    private String convertOwnerCO(Integer fieldType,String asField, String originalAttr,Boolean isOAttrNull) {
        if (Objects.equals(FieldTypeEnum.OWNERID.getType(),fieldType)) {
            originalAttr = XbbConstant.MY_TEAM_MAIN + StringConstant.POSITIVE_NUMBER;
            asField = XbbConstant.MY_TEAM_MAIN + asField.split(XbbConstant.SEPARATOR)[1];
        }
        if (Objects.equals(FieldTypeEnum.COUSERID.getType(),fieldType)) {
            originalAttr = XbbConstant.MY_TEAM + StringConstant.POSITIVE_NUMBER;
            asField = XbbConstant.MY_TEAM + asField.split(XbbConstant.SEPARATOR)[1];
        }
        if (isOAttrNull){
            String preNull = XbbConstant.SQL_NULL;
            if (Objects.equals(FieldTypeEnum.OWNERID.getType(),fieldType) || Objects.equals(FieldTypeEnum.COUSERID.getType(),fieldType)){
                preNull = XbbConstant.L_B+XbbConstant.SINGLE_QUOTES+XbbConstant.SINGLE_QUOTES+XbbConstant.R_B;
            }
            originalAttr = preNull;
        }
        originalAttr = originalAttr + XbbConstant.AS + asField;
        return originalAttr;
    }


    @Override
    public String getNodeType() {
        return DataSetNodeTypeEnum.UNION.getAlias();
    }

    @Override
    public String getParseSql(String nodeId) {
        return SQL_NODES_THREAD_LOCAL.get().get(nodeId);
    }
}
